﻿using ConsoleHoster.Common.UserInput;
using ConsoleHoster.Common.Utilities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Windows.Input;

namespace ConsoleHoster.Common.UnitTests.UserInput
{
	[TestClass]
	public class KeyboardInputHandlerTests
	{
		private KeyboardInputHandler keyboardInputHandler;
		private Mock<IKeyboardStateProvider> mockKeyboardStateProvider;
		private Mock<ILogger> mockLogger;

		[TestInitialize]
		public void Initialize()
		{
			this.mockLogger = new Mock<ILogger>();
			this.mockKeyboardStateProvider = new Mock<IKeyboardStateProvider>();
			this.keyboardInputHandler = new KeyboardInputHandler(this.KeyboardStateProvider, this.Logger);
		}

		[TestMethod]
		public void HandleKeyboardInput_CallsRegisteredHandlerWithNullContext()
		{
			Key tmpSpecialKey = Key.Tab;
			string tmpContext = null;
			bool tmpHandlerCalled = false;

			this.keyboardInputHandler.RegisterHandler(tmpSpecialKey, null, tmpContext, ksp =>
			{
				tmpHandlerCalled = true;
				return true;
			});

			this.keyboardInputHandler.HandleKeyboardInput(tmpSpecialKey, tmpContext);

			Assert.IsTrue(tmpHandlerCalled);
		}

		[TestMethod]
		public void HandleKeyboardInput_RegisteredHandlerNotCalledForUnrelatedKey()
		{
			Key tmpSpecialKey = Key.Tab;
			Key tmpOtherKey = Key.N;
			string tmpContext = "some context";
			bool tmpHandlerCalled = false;

			this.keyboardInputHandler.RegisterHandler(tmpSpecialKey, null, tmpContext, ksp =>
			{
				tmpHandlerCalled = true;
				return true;
			});

			this.keyboardInputHandler.HandleKeyboardInput(tmpOtherKey, tmpContext);

			Assert.IsFalse(tmpHandlerCalled);
		}

		[TestMethod]
		public void HandleKeyboardInput_CallsRegisteredHandlerWithContext()
		{
			Key tmpSpecialKey = Key.Tab;
			string tmpContext = "any context";
			bool tmpHandlerCalled = false;

			this.keyboardInputHandler.RegisterHandler(tmpSpecialKey, null, tmpContext, ksp =>
			{
				tmpHandlerCalled = true;
				return true;
			});

			this.keyboardInputHandler.HandleKeyboardInput(tmpSpecialKey, tmpContext);

			Assert.IsTrue(tmpHandlerCalled);
		}

		[TestMethod]
		public void HandleKeyboardInput_HandlesExceptionsFromUnderlyingHandler()
		{
			Key tmpAnyKey = Key.A;
			string tmpContext = null;

			this.keyboardInputHandler.RegisterHandler(tmpAnyKey, null, tmpContext, ksp =>
			{
				throw new Exception("Any unexpected error");
			});

			this.keyboardInputHandler.HandleKeyboardInput(tmpAnyKey, tmpContext);
		}

		private IKeyboardStateProvider KeyboardStateProvider
		{
			get
			{
				return this.mockKeyboardStateProvider.Object;
			}
		}

		private ILogger Logger
		{
			get
			{
				return this.mockLogger.Object;
			}
		}
	}
}
